Table locations;
int rowCount, curPoint;
PImage mapImage;
PVector []ellipsePos;
static float epsilon = 0.0001;
PVector []startPt;
PVector []endPt;
PVector []speed;
int []curPos;
boolean debug = false;
static int numOfPoints = 1000;

void setup()
{
  // load data and map
  mapImage = loadImage("../res/map.png");
  locations = new Table("../res/locations.tsv");
  rowCount = locations.getRowCount();

  // prepare moving points
  curPos = new int[numOfPoints];
  for (int i=0; i<numOfPoints; ++i) {
    curPos[i] = (int)random(0, rowCount);
  }
  startPt = new PVector[numOfPoints];
  endPt = new PVector[numOfPoints];
  speed = new PVector[numOfPoints];
  ellipsePos = new PVector[numOfPoints];
  
  for (int i=0; i<numOfPoints; ++i) {
    startPt[i] = new PVector(locations.getFloat(curPos[i], 0), 
                             locations.getFloat(curPos[i], 1));
    int next = randomPick(curPos[i]);
    endPt[i] = new PVector(locations.getFloat(next, 0),
                           locations.getFloat(next, 1));
    speed[i] = new PVector();
    getSpeed(speed[i], startPt[i], endPt[i]);
    ellipsePos[i] = new PVector(startPt[i].x, startPt[i].y);
    curPos[i] = next;
  }
  // setup
  size(mapImage.width, mapImage.height);
  smooth();
  noStroke();
}

void getSpeed(PVector speed, PVector startPos, PVector endPos)
{
  speed.x = endPos.x - startPos.x;
  speed.y = endPos.y - startPos.y;
  speed.normalize();
}

void draw()
{
  image(mapImage, 0, 0);
  
  // draw all cities
  fill(0);
  for (int row=0; row<rowCount; ++row) {
    float x = locations.getFloat(row, 0);
    float y = locations.getFloat(row, 1);
    ellipse(x, y, 9, 9);
  }
  
  for (int i=0; i<numOfPoints; ++i) {
    if (debug) {
      println("startPos.x " + startPt[i].x + " startPos.y" + startPt[i].y);
      println("endPos.x " + endPt[i].x + " endPos.y " + endPt[i].y);
      println("ellipse.x " + ellipsePos[i].x + " ellipse.y " + ellipsePos[i].y);
      println("curPos " + curPos[i]);
    }
    fill((i * 10) % 250, (i * 50) % 250, (i * 100) % 255);
    if (isOnline(ellipsePos[i], startPt[i], endPt[i])) {
      ellipse(ellipsePos[i].x, ellipsePos[i].y, 5, 5);
      ellipsePos[i].add(speed[i]);
    } else {
      int next = randomPick(curPos[i]);
      if (debug) 
        println("next point " + curPos[i]);
      ellipsePos[i].x = locations.getFloat(curPos[i], 0);
      ellipsePos[i].y = locations.getFloat(curPos[i], 1);
      startPt[i].x = ellipsePos[i].x;
      startPt[i].y = ellipsePos[i].y;
      endPt[i].x = locations.getFloat(next, 0);
      endPt[i].y = locations.getFloat(next, 1);
      getSpeed(speed[i], startPt[i], endPt[i]);
      curPos[i] = next;
    }
  }
}

int randomPick(int cur)
{
  int ret;
  do {
    ret = (int)random(0, rowCount);
  } while (ret == cur);
  return ret;
}

// AABB
boolean isOnline(PVector pt, PVector startPos, PVector endPos)
{
  float leftmost = min(startPos.x, endPos.x);
  float rightmost = max(startPos.x, endPos.x);
  float topmost = min(startPos.y, endPos.y);
  float bottommost = max(startPos.y, endPos.y);
  return (pt.x >= leftmost && pt.x <= rightmost && pt.y >= topmost && pt.y <= bottommost);
}

class Table {
  float[][] data;
  int rowCount;
  
  Table() 
  {
    data = new float[10][10];
  }
  
  Table(String filename)
  {
    String[] rows = loadStrings(filename);
    data = new float[rows.length][];
    rowCount = rows.length;
    for (int i=0; i<rows.length; ++i) {
      if (trim(rows[i]).length() == 0
          || rows[i].startsWith("#")) {
            continue; // Skip blank lines and comment lines
      }
      String []str = split(rows[i], TAB);
      data[i] = new float[str.length - 1];
      for (int t=1; t<str.length; ++t) {
        data[i][t-1] = parseFloat(str[t]);
        println("insert row " + i + " data: " + data[i][t-1]);
      }
    }
    //data = (float[][])subset(data, 0, rowCount);
  }
  
  int getRowCount()
  {
    return rowCount;
  }
  
  float getFloat(int rowIndex, int column) 
  {
    return data[rowIndex][column];
  }
  
  float getString(int rowIndex, int column)
  {
    return data[rowIndex][column];
  }
 
}
